/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.googlecode.datawander.Presenter;

import com.googlecode.datawander.View.ConnectionValues;
import com.googlecode.datawander.codecompiler.CodeCompiler;
import com.googlecode.datawander.codecompiler.CompileCodeException;
import com.googlecode.datawander.codeexecutor.MyGeneratedCodeLoader;
import com.googlecode.datawander.codeexecutor.CodeRunException;
import com.googlecode.datawander.codegenerator.CodeGenerationException;
import com.googlecode.datawander.codegenerator.SourceCodeGenerator2Object;
import com.googlecode.datawander.connectors.Db4oUtil;
import com.googlecode.datawander.connectors.MyRelationalDataBaseException;
import com.googlecode.datawander.connectors.OracleConnector;
import com.googlecode.datawander.i18n.I18n;
import com.googlecode.datawander.shemareader.MetaClass;
import com.googlecode.datawander.shemareader.OracleDatabaseSchemaReader;
import java.io.File;
import java.util.logging.Level;
import org.apache.log4j.Logger;



/**
 *
 * @author Marcin Stachniuk
 */
public class Relational2ObjectMigrationThread extends Thread {

    private static final Logger logger = Logger.getLogger(Relational2ObjectMigrationThread.class);
    private static final String GENERATED_CODE_FOLDER_NAME = "generatedCode";
    private static final String COMPILED_CODE_FOLDER_NAME = "compiledCode";
    private DataWanderViewInt dataWanderView;
    private ConnectionValues connectionValues;
    private DataWanderPresenterInt dataWanderPresenter;
    private static final int PROGRESS = 12;


    @Override
    public void run() {
        logger.trace("Relational2ObjectMigrationThread run()");
        try {
            migrationProcess();
        } catch (CodeRunException ex) {
            logger.debug(ex, ex);
            dataWanderView.enterLog(I18n.getString("cannotinvokemethod"));
            dataWanderView.showErrorMessage();
        } catch (ClassNotFoundException ex) {
            logger.debug(ex, ex);
            dataWanderView.enterLog(I18n.getString("classnotfoudproblem"));
            dataWanderView.showErrorMessage();
        } catch (CodeGenerationException ex) {
            logger.debug(ex, ex);
            dataWanderView.enterLog(I18n.getString("relationaldatabaseexceptionproblem"));
            dataWanderView.showErrorMessage();
        } catch (MyRelationalDataBaseException ex) {
            logger.debug(ex, ex);
            dataWanderView.enterLog(I18n.getString("relationaldatabaseexceptionproblem"));
            dataWanderView.showErrorMessage();
        } catch (CompileCodeException ex) {
            logger.debug(ex, ex);
            dataWanderView.enterLog(I18n.getString("nojavaccompiler"));
            dataWanderView.showErrorMessage();
        }
        finally {
            // inform controler about end of migration process
            dataWanderPresenter.endMigrationProcess();
            Db4oUtil.closeObjectContainer();
            Db4oUtil.shutdown();
        }
    }

    public void setDataWanderView(DataWanderViewInt dataWanderView) {
        this.dataWanderView = dataWanderView;
    }

    public void setConnectionValues(ConnectionValues connectionValues) {
        this.connectionValues = connectionValues;
    }

    public void setDataWanderPresenter(DataWanderPresenterInt dataWanderPresenter) {
        this.dataWanderPresenter = dataWanderPresenter;
    }

    /**
     * Main migration process
     * @throws CompileCodeException
     * @throws MyRelationalDataBaseException
     * @throws CodeGenerationException
     * @throws ClassNotFoundException
     * @throws CodeRunException
     */
    public void migrationProcess() throws CompileCodeException,
            MyRelationalDataBaseException, CodeGenerationException,
            ClassNotFoundException, CodeRunException {
        // test is javac instal
        CodeCompiler.isCompilerInstal();
        dataWanderView.enterLog(I18n.getString("compilationTestSuccess"));
        dataWanderView.showMigrationProggres(0);

        // init relational database driver
        OracleConnector.setUsername(connectionValues.getRelationalUsername());
        OracleConnector.setPassword(connectionValues.getRelationalPassword());
        OracleConnector.setUrl(connectionValues.getRelationalURL());
        OracleConnector.initDatabaseDriver();
        dataWanderView.enterLog(I18n.getString("relationaldriverloadedsucesfull"));
        dataWanderView.showMigrationProggres(PROGRESS);


        // read relational database schema
        OracleDatabaseSchemaReader schema = new OracleDatabaseSchemaReader();
        schema.readDatabaseSchema();
        logger.info(I18n.getString("readDatabaseShemaSuccess"));
        schema.showInfoFromMetaClas();
        dataWanderView.showMigrationProggres(2 * PROGRESS);

        String userDir = System.getProperty("user.dir");
        String sourceCodePath = userDir + File.separatorChar +
                GENERATED_CODE_FOLDER_NAME + File.separatorChar;
        String outputCodePath = userDir + File.separatorChar +
                COMPILED_CODE_FOLDER_NAME + File.separatorChar;

        // generate source code
        SourceCodeGenerator2Object sourceCodeGenerator = new SourceCodeGenerator2Object();
        sourceCodeGenerator.generateSourceCode(schema.getMetaClassList(), sourceCodePath);
        dataWanderView.enterLog(I18n.getString("codegeneratesucess"));
        dataWanderView.showMigrationProggres(3 * PROGRESS);

        // compile source code
        CodeCompiler codeCompiler = new CodeCompiler();
        codeCompiler.compileSourceCode(sourceCodePath, outputCodePath);
        dataWanderView.enterLog(I18n.getString("compilationCodeSuccess"));
        dataWanderView.showMigrationProggres(4 * PROGRESS);

        // load all compiled classes
        MyGeneratedCodeLoader codeLoader = new MyGeneratedCodeLoader(outputCodePath);
        codeLoader.loadAllCompiledClasses();
        dataWanderView.enterLog(I18n.getString("loadAllClassesSuccess"));
        dataWanderView.showMigrationProggres(5 * PROGRESS);

        // sets relational database connetions parametrs
        codeLoader.setRealtionalDatabaseParametrs(connectionValues.getRelationalURL(),
                connectionValues.getRelationalUsername(),
                connectionValues.getRelationalPassword());
        dataWanderView.enterLog(I18n.getString("setConectionParametrsWithDatabaseSuccess"));
        dataWanderView.showMigrationProggres(6 * PROGRESS);

        //TODO: test exist ObjectFilename and add question about delete this file

        // set object database file
        codeLoader.setDb4oFilename(connectionValues.getObjectFilename());

        String [] classNames = schema.getTabOfAllClassNames();

        for(String s : classNames) {
            Object allRecords = codeLoader.invokeLoadAllRecords(s);

            String message = I18n.getString("loadallrecordsbyclass");
            message = String.format(message, s);
            dataWanderView.enterLog(message);

            if(allRecords instanceof Object []) {
                Object [] allRecordsTab = (Object []) allRecords;

                codeLoader.saveObjectsInDb4o(s, allRecordsTab);
                message = I18n.getString("saveallrecordsinobjectdatabase");
                message = String.format(message, s);
                dataWanderView.enterLog(message);
            } else {
                message = I18n.getString("icannotcastobectontabofobcjets");
                logger.error(message);
                dataWanderView.enterLog(message);
            }
        }

        // update M:N references
        for(MetaClass mc : schema.getMetaClassList()) {
            if(mc.isAssociationClass()) {
                codeLoader.updateManyToManyObjects(mc);
            }
        }

        // close objectdatabase
        codeLoader.closeDb4o();

        codeLoader.defragObjectDatabase();

        Db4oUtil.closeObjectContainer();
        Db4oUtil.shutdown();

        dataWanderView.showMigrationProggres(100);
        dataWanderView.showSucessMessage();
    }
}
